/*
 * Copyright (c) 2021 Huawei Device Co.,  Ltd.
 * Licensed under the Apache License,  Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,  software
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,  either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <napi/native_common.h>
#include <napi/native_api.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <recptprinter_def.h>
#include "recptprinter_srv_client.h"
#include "recptprinter_hilog.h"
#include "recptprinter_utils.h"
#include "cashdevice_napi.h"
#include "recptprinter_observer.h"

using namespace SwanLink::Finance;

thread_local static RecptprinterSrvClient& g_recptprinterClient = RecptprinterSrvClient::GetInstance();
static PrinterObserver *g_pOberserver = nullptr;
/**
 * @brief 定义接口函数
 * static napi_value XXXX(napi_env env,  napi_callback_info info)
 * @param env 
 * @param info 
 * @return napi_value 
 */
static napi_value GetPrintFormat(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = {0};
    struct tTmpStruct{
        int handle;
        PrintFormatType ftt;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 2,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], reinterpret_cast<int32_t*>(&pVar->ftt)));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        PrintFormatType &ftt = pVar->ftt;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.GetPrintFormat(handle, ftt);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}
static napi_value SetPrintFormat(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 3;
    napi_value args[3] = {0};
    struct tTmpStruct{
        int handle;
        PrintFormatType ftt;
        int value;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 3,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], reinterpret_cast<int32_t*>(&pVar->ftt)));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->value));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        PrintFormatType &ftt = pVar->ftt;
        int &value = pVar->value;

        g_recptprinterClient.SetPrintFormat(handle, ftt, value);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result = nullptr;
        NAPI_CALL(env, napi_create_int32(env, pVar->value, &result));
        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}
static napi_value GetDeviceSpec(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 1;
    napi_value args[2] = {0};
    struct tTmpStruct{
        int handle;
        DeviceSpec spec;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 1,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        DeviceSpec &spec = pVar->spec;

        g_recptprinterClient.GetDeviceSpec(handle, spec);
        RECPTPRINTER_HILOGD(RECPTPRINTER_JS_NAPI, "canCutPaper = %{public}d, setDensity = %{public}d, width = %{public}f",
            spec.canCutPaper, spec.setDensity, spec.width);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result = nullptr;

        RECPTPRINTER_HILOGD(RECPTPRINTER_JS_NAPI, "canCutPaper = %{public}d, setDensity = %{public}d, width = %{public}f",
            pVar->spec.canCutPaper, pVar->spec.setDensity, pVar->spec.width);
        NAPI_CALL(env, napi_create_object(env, &result));

        NAPI_OBJECT_PROP_SET_BOOL(result, "canCutPaper", pVar->spec.canCutPaper);
        NAPI_OBJECT_PROP_SET_BOOL(result, "setDensity", pVar->spec.setDensity);
        NAPI_OBJECT_PROP_SET(result, double, "width", pVar->spec.width);
        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "GetDeviceSpec", async);
}
static napi_value FeedPaper(napi_env env,  napi_callback_info info) {
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 2;
    napi_value args[2] = {0};
    struct tTmpStruct{
        int handle;
        int line;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 2,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->line));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &line = pVar->line;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.FeedPaper(handle, line);

        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "FeedPaper", async);
}
static napi_value CutPaper(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 3;
    napi_value args[3] = {0};
    struct tTmpStruct{
        int handle;
        int line;
        int mode;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 3,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->line));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->mode));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &line = pVar->line;
        int &mode = pVar->mode;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.CutPaper(handle, line, mode);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncPromise(env, "CutPaper", async);
}
static napi_value AddText(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 4;
    napi_value args[4] = {0};
    struct tTmpStruct{
        int handle;
        int x;
        int y;
        std::string text;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 4,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->x));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->y));
    char text_buf[1024] = {0};
    size_t text_len = 0;
    NAPI_CALL(env, napi_get_value_string_utf8(env, args[3], text_buf, sizeof(text_buf), &text_len));
    pVar->text = text_buf;

    RECPTPRINTER_HILOGE(RECPTPRINTER_JS_NAPI,
        "AddText x = %{public}d, y = %{public}d, text = %{public}s, text_len = %{public}d",
        pVar->x, pVar->y, text_buf, (int)text_len);

    RECPTPRINTER_HILOGE(RECPTPRINTER_JS_NAPI, "AddText pVar->text = %{public}s", pVar->text.c_str());

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &x = pVar->x;
        int &y = pVar->y;
        std::string &text = pVar->text;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.AddText(handle, x, y, text);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}
static napi_value AddBitmap(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 4;
    napi_value args[4] = {0};
    struct tTmpStruct{
        int handle;
        int x;
        int y;
        char lpath[256];
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 4,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->x));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->y));
    size_t path_len;
    NAPI_CALL(env, napi_get_value_string_utf8(env, args[3], pVar->lpath, sizeof(pVar->lpath), &path_len));

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &x = pVar->x;
        int &y = pVar->y;
        char *lpath = pVar->lpath;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.AddBitmap(handle, x, y, lpath);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}

static napi_value AddQRCode(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 5;
    napi_value args[5] = {0};
    struct tTmpStruct{
        int handle;
        int x;
        int y;
        int w;
        std::string qr;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 5,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->x));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->y));
    NAPI_CALL(env, napi_get_value_int32(env, args[3], &pVar->w));
    char qr_buf[256];
    size_t qr_len;
    NAPI_CALL(env, napi_get_value_string_utf8(env, args[4], qr_buf, sizeof(qr_buf), &qr_len));
    pVar->qr = qr_buf;

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &x = pVar->x;
        int &y = pVar->y;
        int &w = pVar->w;
        std::string &qr = pVar->qr;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.AddQRCode(handle, x, y, w, qr);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}
static napi_value AddBarCode(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 5;
    napi_value args[5] = {0};
    struct tTmpStruct{
        int handle;
        int x;
        int y;
        BarCodeSpec spec;
        std::string bar;
        int ret;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 5,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->x));
    NAPI_CALL(env, napi_get_value_int32(env, args[2], &pVar->y));
    NAPI_OBJECT_PROP_GET(args[3], int32, "height", (int32_t*)&pVar->spec.height);
    NAPI_OBJECT_PROP_GET(args[3], int32, "narrow", (int32_t*)&pVar->spec.narrow);
    NAPI_OBJECT_PROP_GET(args[3], int32, "wide", (int32_t*)&pVar->spec.wide);
    NAPI_OBJECT_PROP_GET(args[3], int32, "hri", (int32_t*)&pVar->spec.hri);
    char bar_buf[1024];
    size_t bar_len;
    NAPI_CALL(env, napi_get_value_string_utf8(env, args[4], bar_buf, sizeof(bar_buf), &bar_len));
    pVar->bar = bar_buf;

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &x = pVar->x;
        int &y = pVar->y;
        BarCodeSpec &spec = pVar->spec;
        std::string &bar = pVar->bar;
        int &ret = pVar->ret;

        ret = g_recptprinterClient.AddBarCode(handle, x, y, spec, bar);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        napi_value result;
        NAPI_CALL(env, napi_create_int32(env, pVar->ret, &result));

        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return NapiCall(env, async);
}
static napi_value StartPrint(napi_env env,  napi_callback_info info)
{
    napi_value this_arg = nullptr;
    void *priv_data = nullptr;
    size_t argc = 3;
    napi_value args[3] = {0};
    struct tTmpStruct{
        int handle;
        PrinterObserver* listener;
        int timeout;
    };

    tTmpStruct *pVar = new tTmpStruct();

    NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &this_arg, &priv_data));
    NAPI_ASSERT(env,  argc >= 3,  "Wrong number of arguments");
    NAPI_CALL(env, napi_get_value_int32(env, args[0], &pVar->handle));
    NAPI_CALL(env, napi_get_value_int32(env, args[1], &pVar->timeout));

    if (g_pOberserver == nullptr) {
        g_pOberserver = new PrinterObserver();
    }
    pVar->listener = g_pOberserver;
    pVar->listener->PushObserver(env, args[2]);

    async_excute_work work_func = [](napi_env env, size_t argc, napi_value args[], void *data)->napi_status {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        int &handle = pVar->handle;
        int &timeout = pVar->timeout;
        PrintListener* listener = pVar->listener;
        g_recptprinterClient.StartPrint(handle, timeout, listener);
        return napi_ok;
    };
    async_result_work result_func = [] (napi_env env, void *data)->napi_value {
        napi_value result = nullptr;
        NAPI_CALL(env, napi_get_undefined(env, &result));
        return result;
    };
    async_free_work free_func = [] (napi_env env, void *data) {
        tTmpStruct *pVar = reinterpret_cast<tTmpStruct *>(data);
        
        delete pVar;
    };
    AsyncCallback *async = new AsyncCallback(env, argc, args, work_func, result_func, free_func,
        pVar,
        this_arg,
        priv_data);
    return AsyncCall(env, nullptr, "StartPrint", async);
}


/**
 * @brief 定义枚举类型
 */
static napi_value EnumClassConstructor(napi_env env,  napi_callback_info info)
{
    napi_value thisArg = nullptr;
    void* data = nullptr;

    napi_get_cb_info(env,  info,  nullptr,  nullptr,  &thisArg,  &data);

    return thisArg;
}

static napi_value CreateEnumPrintFormatType(napi_env env, napi_value exports)
{
    napi_value values[9] = {0};
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_DENSITY,  &values[0]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_BOLD,  &values[1]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_REVERSE,  &values[2]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_INVERSION,  &values[3]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_LINETHROUGH,  &values[4]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_SIZE,  &values[5]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_ALIGN,  &values[6]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_ITALIC,  &values[7]);
    napi_create_int32(env,  (int32_t)PRINT_FORMAT_HRILOC,  &values[8]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_DENSITY",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_BOLD",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_REVERSE",  values[2]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_INVERSION",  values[3]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_LINETHROUGH",  values[4]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_SIZE",  values[5]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_ALIGN",  values[6]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_ITALIC",  values[7]),
        DECLARE_NAPI_STATIC_PROPERTY("PRINT_FORMAT_HRILOC",  values[8]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "PrintFormatType",  NAPI_AUTO_LENGTH,  EnumClassConstructor,  nullptr, 9,  desc,  &result);
    napi_set_named_property(env,  exports,  "PrintFormatType",  result);
    return exports;
}
static napi_value CreateEnumFormatDensity(napi_env env, napi_value exports)
{
    napi_value values[3] = {0};
    napi_create_int32(env,  (int32_t)PF_DENSITY_LIGHT,  &values[0]);
    napi_create_int32(env,  (int32_t)PF_DENSITY_MEDIUM,  &values[1]);
    napi_create_int32(env,  (int32_t)PF_DENSITY_DARK,  &values[2]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PF_DENSITY_LIGHT",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_DENSITY_MEDIUM",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_DENSITY_DARK",  values[2]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "FormatDensity",  NAPI_AUTO_LENGTH,  EnumClassConstructor,  nullptr, 3,  desc,  &result);
    napi_set_named_property(env,  exports,  "FormatDensity",  result);
    return exports;
}
static napi_value CreateEnumFormatLineThrough(napi_env env, napi_value exports)
{
    napi_value values[3] = {0};
    napi_create_int32(env,  (int32_t)PF_LINETHROUGH_NONE,  &values[0]);
    napi_create_int32(env,  (int32_t)PF_LINETHROUGH_CONTINIOUS,  &values[1]);
    napi_create_int32(env,  (int32_t)PF_LINETHROUGH_BROKEN,  &values[2]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PF_LINETHROUGH_NONE",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_LINETHROUGH_CONTINIOUS",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_LINETHROUGH_BROKEN",  values[2]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "FormatLineThrough",  NAPI_AUTO_LENGTH,
        EnumClassConstructor,  nullptr, 3,  desc,  &result);
    napi_set_named_property(env,  exports,  "FormatLineThrough",  result);
    return exports;
}
static napi_value CreateEnumFormatSize(napi_env env, napi_value exports)
{
    napi_value values[5] = {0};
    napi_create_int32(env,  (int32_t)PF_SIZE_EXTRASMALL,  &values[0]);
    napi_create_int32(env,  (int32_t)PF_SIZE_SMALL,  &values[1]);
    napi_create_int32(env,  (int32_t)PF_SIZE_MEDIUM,  &values[2]);
    napi_create_int32(env,  (int32_t)PF_SIZE_LARGE,  &values[3]);
    napi_create_int32(env,  (int32_t)PF_SIZE_EXTRALARGE,  &values[4]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PF_SIZE_EXTRASMALL",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_SIZE_SMALL",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_SIZE_MEDIUM",  values[2]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_SIZE_LARGE",  values[3]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_SIZE_EXTRALARGE",  values[4]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "FormatSize",  NAPI_AUTO_LENGTH,  EnumClassConstructor,  nullptr, 5,  desc,  &result);
    napi_set_named_property(env,  exports,  "FormatSize",  result);
    return exports;
}
static napi_value CreateEnumFormatAlign(napi_env env, napi_value exports)
{
    napi_value values[3] = {0};
    napi_create_int32(env,  (int32_t)PF_ALIGN_LEFT,  &values[0]);
    napi_create_int32(env,  (int32_t)PF_ALIGN_CENTER,  &values[1]);
    napi_create_int32(env,  (int32_t)PF_ALIGN_RIGHT,  &values[2]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PF_ALIGN_LEFT",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_ALIGN_CENTER",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_ALIGN_RIGHT",  values[2]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "FormatAlign",  NAPI_AUTO_LENGTH,  EnumClassConstructor,  nullptr, 3,  desc,  &result);
    napi_set_named_property(env,  exports,  "FormatAlign",  result);
    return exports;
}
static napi_value CreateEnumFormatHRILOC(napi_env env, napi_value exports)
{
    napi_value values[4] = {0};
    napi_create_int32(env,  (int32_t)PF_HRILOC_NONE,  &values[0]);
    napi_create_int32(env,  (int32_t)PF_HRILOC_UP,  &values[1]);
    napi_create_int32(env,  (int32_t)PF_HRILOC_DOWN,  &values[2]);
    napi_create_int32(env,  (int32_t)PF_HRILOC_UPDOWN,  &values[3]);
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_STATIC_PROPERTY("PF_HRILOC_NONE",  values[0]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_HRILOC_UP",  values[1]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_HRILOC_DOWN",  values[2]),
        DECLARE_NAPI_STATIC_PROPERTY("PF_HRILOC_UPDOWN",  values[3]),
    };
    napi_value result = nullptr;
    napi_define_class(env,  "FormatHRILOC",  NAPI_AUTO_LENGTH,  EnumClassConstructor,  nullptr, 4,  desc,  &result);
    napi_set_named_property(env,  exports,  "FormatHRILOC",  result);
    return exports;
}

static napi_value CreateEnumStatusCode(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
    DECLARE_CONST_VAR(ERR_PRINTER_BUSY),
    DECLARE_CONST_VAR(ERR_PRINTER_OUT_OF_PAPER),
    DECLARE_CONST_VAR(ERR_PRINTER_NO_TASK),
    DECLARE_CONST_VAR(ERR_PRINTER_FORMAT_NOT_SUPPORT),
    DECLARE_CONST_VAR(ERR_PRINTER_VALUE_OUT_RANGE),
    DECLARE_CONST_VAR(ERR__PRINTER_DATA_PACKET_ERROR),
    DECLARE_CONST_VAR(ERR_PRINTER_HW_ERROR),
    DECLARE_CONST_VAR(ERR_PRINTER_OVERHEATING),
    DECLARE_CONST_VAR(ERR_PRINTER_LOW_VOLTAGE),
    DECLARE_CONST_VAR(ERR_PRINT_UNFINISHED),
    DECLARE_CONST_VAR(ERR_PRINTER_DATA_TOO_LONG),
    DECLARE_CONST_VAR(ERR_PRINTER_DATA_TOO_SHORT),
    DECLARE_CONST_VAR(ERR__PRINTER_FONT_NOT_EXIST),
    DECLARE_CONST_VAR(ERR_PRINTER_CAP_OPEN),

    DECLARE_CONST_VAR(ERR_PRINTER_QUERY_ERROR),
    DECLARE_CONST_VAR(ERR_PRINTER_CUT_ERROR),
    DECLARE_CONST_VAR(ERR_PRINTER_CUT_BROKEN),
    DECLARE_CONST_VAR(ERR_PRINTER_OFFLINE),
    DECLARE_CONST_VAR(ERR_PRINTER_ONLINE_ERROR),
    };

    napi_value result;
    bool has = false;
    napi_has_named_property(env, exports, "StatusCode", &has);
    if (!has) {
        napi_define_class(env,  "StatusCode",  NAPI_AUTO_LENGTH,  EnumClassConstructor,
        nullptr, sizeof(desc)/sizeof(desc[0]), desc,  &result);
        napi_set_named_property(env,  exports,  "StatusCode",  result);
    } else {
        napi_get_named_property(env, exports, "StatusCode", &result);
        for (uint32_t i = 0; i < sizeof(desc)/sizeof(desc[0]); i++) {
            napi_set_named_property(env, result, desc[i].utf8name, desc[i].value);
        }
    }
    return result;
}

napi_value RecptPrinterConstructor(napi_env env, napi_callback_info info)
{
    napi_value thisVar = nullptr;
    napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
    return thisVar;
}

napi_value DefineRecptPrinterClass(napi_env env, napi_value exports)
{
    napi_value RecptPrinter;
    napi_property_descriptor properties[] = {
    DECLARE_NAPI_FUNCTION("GetSupportAccess",  Common::GetSupportAccess),
    DECLARE_NAPI_FUNCTION("Open",  Common::Open),
    DECLARE_NAPI_FUNCTION("Close",  Common::Close),
    DECLARE_NAPI_FUNCTION("QueryStatus",  Common::QueryStatus),
    DECLARE_NAPI_FUNCTION("Reset",  Common::Reset),
    DECLARE_NAPI_FUNCTION("GetPrintFormat",  GetPrintFormat),
    DECLARE_NAPI_FUNCTION("SetPrintFormat",  SetPrintFormat),
    DECLARE_NAPI_FUNCTION("GetDeviceSpec",  GetDeviceSpec),
    DECLARE_NAPI_FUNCTION("FeedPaper",  FeedPaper),
    DECLARE_NAPI_FUNCTION("CutPaper",  CutPaper),
    DECLARE_NAPI_FUNCTION("AddText",  AddText),
    DECLARE_NAPI_FUNCTION("AddBitmap",  AddBitmap),
    DECLARE_NAPI_FUNCTION("AddQRCode",  AddQRCode),
    DECLARE_NAPI_FUNCTION("AddBarCode",  AddBarCode),
    DECLARE_NAPI_FUNCTION("StartPrint",  StartPrint),
    };

    // napi_define_class(env, "RecptPrinter", NAPI_AUTO_LENGTH, RecptPrinterConstructor, nullptr,
    //     sizeof(properties) / sizeof(properties[0]), properties, &RecptPrinter);
    // napi_value napi_inst;
    // napi_new_instance(env, constructor, 0, nullptr, &napi_inst);

    napi_create_object(env, &RecptPrinter);
    napi_define_properties(env, RecptPrinter, sizeof(properties) / sizeof(properties[0]), properties);
    napi_set_named_property(env, exports, "RecptPrinter", RecptPrinter);

    RECPTPRINTER_HILOGI(RECPTPRINTER_JS_NAPI, "RecptPrinter Class defined finished");
    return exports;
}

EXTERN_C_START
/*
 * function for module exports
 */
static napi_value RecptprinterInit(napi_env env,  napi_value exports)
{
    RECPTPRINTER_HILOGD(RECPTPRINTER_JS_NAPI,  "Enter");
    Common::ClientInit(dynamic_cast<CashDeviceClient*>(&g_recptprinterClient), env, exports);

    // 枚举类型
    CreateEnumStatusCode(env,  exports);
    CreateEnumPrintFormatType(env,  exports);
    CreateEnumFormatDensity(env,  exports);
    CreateEnumFormatLineThrough(env,  exports);
    CreateEnumFormatSize(env,  exports);
    CreateEnumFormatAlign(env,  exports);
    CreateEnumFormatHRILOC(env,  exports);

    // 接口申明
    DefineRecptPrinterClass(env, exports);

    RECPTPRINTER_HILOGD(RECPTPRINTER_JS_NAPI,  "Success");

    return exports;
}
EXTERN_C_END

/*
 * Module definition
 */
static napi_module g_module = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = "recptprinter",
    .nm_register_func = RecptprinterInit,
    .nm_modname = "recptprinter",
    .nm_priv = ((void*)0),
    .reserved = {0}
};
/*
 * Module registration
 */
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
    napi_module_register(&g_module);
}
